package ci.model;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

public class RecomendationsCI {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		
		//criticos a las peliculas
		HashMap<String,HashMap> dictionaryTransform=new HashMap<String, HashMap>();
		
		//peliculas a criticos
		HashMap<String,HashMap> dictionary=new HashMap<String, HashMap>();
		HashMap<String, Double> data = new HashMap<String, Double>();
		data.put("Lady in the Water", 2.5);
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 3.0);
		data.put("Superman Returns", 3.5);
		data.put("You, Me and Dupree", 2.5);
		data.put("The Night Listener", 3.0);		
		dictionary.put("Lisa Rose", data);
                
        data = new HashMap<String, Double>();
        data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 1.5);
		data.put("Superman Returns", 5.0);
		data.put("You, Me and Dupree", 3.5);
		data.put("The Night Listener", 3.0);
		dictionary.put("Gene Seymour", data);
		
		data = new HashMap<String, Double>();
        data.put("Lady in the Water", 2.5);
		data.put("Snakes on a Plane", 3.0);		
		data.put("Superman Returns", 3.5);		
		data.put("The Night Listener", 4.0);		
		dictionary.put("Michael Phillips", data);
		
		data = new HashMap<String, Double>();
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 3.0);
		data.put("Superman Returns", 4.0);
		data.put("You, Me and Dupree", 2.5);
		data.put("The Night Listener", 4.5);
		dictionary.put("Claudia Puig", data);       
		
		data = new HashMap<String, Double>();
		data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 4.0);
		data.put("Just My Luck", 2.0);
		data.put("Superman Returns", 3.0);
		data.put("You, Me and Dupree", 2.0);
		data.put("The Night Listener", 3.0);
		dictionary.put("Mick LaSalle", data);
				
		data = new HashMap<String, Double>();
		data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 4.0);		
		data.put("Superman Returns", 5.0);
		data.put("You, Me and Dupree", 3.5);
		data.put("The Night Listener", 3.0);
		dictionary.put("Jack Matthews", data);
		
		data = new HashMap<String, Double>();		
		data.put("Snakes on a Plane", 4.5);		
		data.put("Superman Returns", 4.0);
		data.put("You, Me and Dupree", 1.0);
		dictionary.put("Toby", data);
		
		//criticos a las peliculas    	
		HashMap<String, Double> dataTrans = new HashMap<String, Double>();
		dataTrans.put("Lisa Rose", 2.5);
		dataTrans.put("Gene Seymour", 3.0);
		dataTrans.put("Michael Phillips", 2.5);
		dataTrans.put("Mick LaSalle", 3.0);
		dataTrans.put("Jack Matthews", 3.0);			
		dictionaryTransform.put("Lady in the Water", dataTrans);
		
        
        dataTrans = new HashMap<String, Double>();
        dataTrans.put("Gene Seymour", 3.5);
		dataTrans.put("Lisa Rose", 3.5);
		dataTrans.put("Michael Phillips", 3.0);
		dataTrans.put("Claudia Puig", 3.5);
		dataTrans.put("Mick LaSalle", 4.0);
		dataTrans.put("Jack Matthews", 4.0);
		dataTrans.put("Toby", 4.0);
		dictionaryTransform.put("Snakes on a Plane", dataTrans);
		
		dataTrans = new HashMap<String, Double>();
        dataTrans.put("Lisa Rose", 3.5);
		dataTrans.put("Gene Seymour", 5.0);		
		dataTrans.put("Michael Phillips", 3.5);		
		dataTrans.put("Claudia Puig", 4.0);
		dataTrans.put("Mick LaSalle", 3.0);
		dataTrans.put("Jack Matthews", 5.0);
		dataTrans.put("Toby", 4.0);
		dictionaryTransform.put("Superman Returns", dataTrans);
		
		dataTrans = new HashMap<String, Double>();
		dataTrans.put("Lisa Rose", 2.5);
		dataTrans.put("Gene Seymour", 3.5);
		dataTrans.put("Claudia Puig", 2.5);
		dataTrans.put("Mick LaSalle", 2.0);
		dataTrans.put("Jack Matthews", 3.5);
		dataTrans.put("Toby", 1.0);
		dictionaryTransform.put("You, Me and Dupree", dataTrans);       
					
		dataTrans = new HashMap<String, Double>();
		dataTrans.put("Lisa Rose", 3.0);
		dataTrans.put("Gene Seymour", 3.0);		
		dataTrans.put("Michael Phillips", 4.0);
		dataTrans.put("Claudia Puig", 4.5);
		dataTrans.put("Mick LaSalle", 3.0);
		dataTrans.put("Jack Matthews", 3.0);		
		dictionaryTransform.put("The Night Listener", dataTrans);
		
		dataTrans = new HashMap<String, Double>();		
		dataTrans.put("Lisa Rose", 3.0);		
		dataTrans.put("Gene Seymour", 1.5);
		dataTrans.put("Claudia Puig", 3.0);
		dataTrans.put("Mick LaSalle", 2.0);				
		dictionaryTransform.put("Just My Luck", dataTrans);
		
    
        System.out.println("Similitud Euclediana: [" +RecomendationsCI.simDistance(dictionary, "Lisa Rose", "Gene Seymour")+"]");
        System.out.println("Similitud Pearson: [" +RecomendationsCI.simPearson(dictionary, "Lisa Rose", "Gene Seymour")+"]");
                       
        SortedMap<Double, String> recomendatiosEuc = RecomendationsCI.getRecomendations(dictionary, "Toby",1);
        System.out.println(" ");
        System.out.println(" ");
        System.out.println("--------Recomendations Eucledian----------------");
        System.out.println(" ");
        
        Map.Entry datos;        
        for (Iterator iterator = recomendatiosEuc.entrySet().iterator(); iterator.hasNext();) {
        	datos  = (Map.Entry) iterator.next();        	
        	System.out.println("Pelicula: " + datos.getValue() + " valor: [" + datos.getKey() +"]" );			
		}
        
        SortedMap<Double, String> recomendatiosPearson = RecomendationsCI.getRecomendations(dictionary, "Toby",2);
        System.out.println(" ");
        System.out.println(" ");
        System.out.println("--------Recomendations Pearson----------------");
        System.out.println(" ");
        
        Map.Entry datosPearson;        
        for (Iterator iterator = recomendatiosPearson.entrySet().iterator(); iterator.hasNext();) {
        	datosPearson  = (Map.Entry) iterator.next();        	
        	System.out.println("Pelicula: " + datosPearson.getValue() + " valor: [" + datosPearson.getKey() +"]" );			
		}
        
                       
        SortedMap<Double, String> topMatches = RecomendationsCI.topMatches(dictionary, "Toby", 6);
        
        Map.Entry pairs;
        System.out.println(" ");
        System.out.println(" ");
        System.out.println("----------Top Matches Personas------------------");
        System.out.println(" ");
        for (Iterator iterator = topMatches.entrySet().iterator(); iterator.hasNext();) {
        	pairs  = (Map.Entry) iterator.next();        	
        	System.out.println("Persona: " + pairs.getValue() + " Valor: [" + pairs.getKey() +"]" );
			
		}
                        
        SortedMap<Double, String> topMatches2 = RecomendationsCI.topMatches(dictionaryTransform, "Superman Returns", 6);
        
        Map.Entry parejas;
        System.out.println(" ");
        System.out.println(" ");
        System.out.println("----------Top Matches Peliculas------------------");
        System.out.println(" ");
        for (Iterator iterator = topMatches2.entrySet().iterator(); iterator.hasNext();) {
        	parejas  = (Map.Entry) iterator.next();        	
        	System.out.println("Persona: " + parejas.getValue() + " Valor: [" + parejas.getKey() +"]" );
			
		}
       
       

    }
   
    public static double simDistance(HashMap<String,HashMap>  prefs, String person1, String person2)
    {     
        List si = new ArrayList(); 
        Iterator it = prefs.get(person1).entrySet().iterator();
        Map.Entry pairs;
        while (it.hasNext()) {
            pairs = (Map.Entry)it.next();
            if ( prefs.get(person2).containsKey(pairs.getKey()) ){            	
            	si.add(pairs.getKey());
            }
            
        }
        if (si.size() == 0) return 0.0;
        double sum_of_squares = 0.0f;
        double oper1;
        double oper2;
        it = prefs.get(person1).entrySet().iterator();
        while (it.hasNext()) {
            pairs = (Map.Entry)it.next();
            if ( prefs.get(person2).containsKey(pairs.getKey()) ){
            	oper1 = Double.parseDouble( prefs.get(person1).get(pairs.getKey()).toString());
            	oper2 = Double.parseDouble( prefs.get(person2).get(pairs.getKey()).toString());
            	oper1 = oper1 - oper2;
            	sum_of_squares += Math.pow(oper1 , 2.0);
            }
            
        }
        //ssreturn 1 / (1+Math.sqrt(sum_of_squares));
        
        return 1 / (1+sum_of_squares);        
    }
    
 public static Double simPearson(HashMap<String, HashMap> prefs, String person1, String person2) {		
		
		HashMap<String, Integer> si = new HashMap<String, Integer>();
		
		Double r = 0D;
		
		// las peliculas del primer critico
		HashMap<String, Double> moviesByCritic1 = prefs.get(person1);		
					
		// las peliculas del segundo critico
		HashMap<String, Double> moviesByCritic2 = prefs.get(person2);		
							
		Iterator<Entry<String, Double>> iteratorCritic1 = 
			moviesByCritic1.entrySet().iterator();				
		
		while(iteratorCritic1.hasNext()) {			
			
			Map.Entry<String, Double> nextMovie = 
				(Map.Entry<String, Double>)iteratorCritic1.next();			
			
			if( moviesByCritic2.containsKey(nextMovie.getKey()) ) {										
				// sirve de validacion
				si.put(nextMovie.getKey(), 1);						
			}			
			
		}// end while				
			
		if(si.size() == 0) {
			return 0D;
		}
		
		int n = si.size();
		
		double sum1 = 0, sum2 = 0;
		
		iteratorCritic1 = moviesByCritic1.entrySet().iterator();
		
		// Sums of all the preferences
		while(iteratorCritic1.hasNext()) {			
			
			Map.Entry<String, Double> nextMovie = 
				(Map.Entry<String, Double>)iteratorCritic1.next();			
			
			if( moviesByCritic2.containsKey(nextMovie.getKey()) ) {										
				sum1+=nextMovie.getValue();
				sum2+=moviesByCritic2.get(nextMovie.getKey());
			}			
			
		}// end while		
		
		double sum1Sq = 0, sum2Sq = 0;
		
		iteratorCritic1 = moviesByCritic1.entrySet().iterator();
		
		// Sums of the squares
		while(iteratorCritic1.hasNext()) {			
			
			Map.Entry<String, Double> nextMovie = 
				(Map.Entry<String, Double>)iteratorCritic1.next();			
			
			if( moviesByCritic2.containsKey(nextMovie.getKey()) ) {										
				sum1Sq+=Math.pow(nextMovie.getValue(), 2);
				sum2Sq+=Math.pow(moviesByCritic2.get(nextMovie.getKey()), 2);
			}			
			
		}// end while
		double pSum = 0;
		
		iteratorCritic1 = moviesByCritic1.entrySet().iterator();
		
		// Sums of the products
		while(iteratorCritic1.hasNext()) {			
			
			Map.Entry<String, Double> nextMovie = 
				(Map.Entry<String, Double>)iteratorCritic1.next();			
			
			if( moviesByCritic2.containsKey(nextMovie.getKey()) ) {										
				Double movieRatingCritic1 =  nextMovie.getValue();
				Double movieRatingCritic2 =  moviesByCritic2.get(nextMovie.getKey());
				
				pSum += (movieRatingCritic1*movieRatingCritic2);
			}			
			
		}// end while
		
		
		 // Calculate r (Pearson score)
		  double num=pSum-(sum1*sum2/n);
		  double den=Math.sqrt((sum1Sq-Math.pow(sum1,2)/n)*(sum2Sq-Math.pow(sum2,2)/n));
		  
		  if(den == 0) {
			  return 0D;
		  }
		  
		r = num/den;
		  
		return r;
    }
    
    
 public static SortedMap<Double, String> topMatches(HashMap<String,HashMap> critics,String person, int n )
 {
	 	SortedMap<Double,String> recomendation=new TreeMap<Double, String>(java.util.Collections.reverseOrder());    	 	
	 	 
     Iterator it = critics.keySet().iterator();
     String otherPerson;
     double avg = 0.0;
     while (it.hasNext()) {
     	otherPerson = (String)it.next();
     	if (person != otherPerson){
     		avg = simPearson(critics, person, otherPerson);
     		recomendation.put(avg, otherPerson);
     	}
     }
     SortedMap<Double,String> recomendationResult =new TreeMap<Double, String>(java.util.Collections.reverseOrder());
     
     if ( n <= 0 ){
     	recomendationResult = recomendation;
     }else{
     	int i = 0;
         Map.Entry pairs;
     	for (Iterator iterator = recomendation.entrySet().iterator(); iterator.hasNext();) {
     		pairs  = (Map.Entry) iterator.next();
     		recomendationResult.put (Double.parseDouble(pairs.getKey().toString()), pairs.getValue().toString());
     		i++;
     		if ( i >= n ){
     			break;
     		}
     	}
     }
	     
     
     return recomendationResult;
 }
    
    
    public static SortedMap<Double, String> getRecomendations(HashMap<String,HashMap> persons,String person,int metodo){
    	Iterator it = persons.keySet().iterator();
    	String otherPerson;
    	HashMap<String,HashMap> otherPersonFull;
    	
    	SortedMap<Double,String> rankings=new TreeMap<Double, String>(java.util.Collections.reverseOrder());
    	
    	HashMap<String, Double> totals = new HashMap<String, Double>();
    	HashMap<String, Double> simSum = new HashMap<String, Double>();
    	
    	double sim = 0.0;
    	double resul = 0.0;
    	while (it.hasNext()) {
        	otherPerson = (String)it.next();
        	if (person != otherPerson){
        		if(metodo == 1){
        			sim = simDistance(persons, person, otherPerson);
        		}
        		else{
        			sim = simPearson(persons, person, otherPerson);
        		}
        			
        		Map.Entry dato;
        		if (sim > 0){
        			//otherPersonFull = persons.get(otherPerson);
        			Iterator it2 = persons.get(otherPerson).entrySet().iterator();
        			// Iterator it2 = otherPersonFull. keySet().iterator();
        			 while(it2.hasNext()){
        				 dato = (Map.Entry)it2.next();
        				 if ( !persons.get(person).containsKey(dato.getKey()) ){
        					 //agregarla y con los demas criticos irle sumando
        					  resul = ((Double) dato.getValue()) * sim ;
        					  //si ya esta agregado al map de resultado sacarlo para sumarle
        					  if(totals.containsKey(dato.getKey())){
        						  double suma = totals.get(dato.getKey()); 
        						  suma = suma + resul;
        						  totals.put(dato.getKey().toString(), suma);
        					  }
        					  else{
        						  totals.put(dato.getKey().toString(), resul);
        					  }
        					  //suma de similitudes
        					  if(simSum.containsKey(dato.getKey())){
        						double sum = simSum.get(dato.getKey());
        						sum = sum + sim;
        						simSum.put(dato.getKey().toString(), sum);
        					  }
        					  else{
        						  simSum.put(dato.getKey().toString(), sim);
        					  }
        				 }//if !persons.get(person).containsKey(dato.getKey()         				         				 
        			 }        			         			        			
        		}//if sim > 0
        	}
        }
    	
    	 Map.Entry dato2;
		 Iterator it3 = totals.entrySet().iterator();
		 while(it3.hasNext()){
			 dato2 = (Map.Entry)it3.next();
			 if(simSum.containsKey(dato2.getKey())){
				 double sum3 = totals.get(dato2.getKey())/simSum.get(dato2.getKey());
				 rankings.put(sum3, dato2.getKey().toString());
			 }			 			
		 }		 		 
    	
    	return rankings;
    	
    }
    
    public HashMap<String,HashMap> info(){
    	HashMap<String,HashMap> dictionary=new HashMap<String, HashMap>();
		HashMap<String, Double> data = new HashMap<String, Double>();
		data.put("Lady in the Water", 2.5);
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 3.0);
		data.put("Superman Returns", 3.5);
		data.put("You, Me and Dupree", 2.5);
		data.put("The Night Listener", 3.0);		
		dictionary.put("Lisa Rose", data);
        
        
        data = new HashMap<String, Double>();
        data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 1.5);
		data.put("Superman Returns", 5.0);
		data.put("You, Me and Dupree", 3.5);
		data.put("The Night Listener", 3.0);
		dictionary.put("Gene Seymour", data);
		
		 data = new HashMap<String, Double>();
        data.put("Lady in the Water", 2.5);
		data.put("Snakes on a Plane", 3.0);		
		data.put("Superman Returns", 3.5);		
		data.put("The Night Listener", 4.0);		
		dictionary.put("Michael Phillips", data);
		
		data = new HashMap<String, Double>();
		data.put("Snakes on a Plane", 3.5);
		data.put("Just My Luck", 3.0);
		data.put("Superman Returns", 4.0);
		data.put("You, Me and Dupree", 2.5);
		data.put("The Night Listener", 4.5);
		dictionary.put("Claudia Puig", data);       
		
		data = new HashMap<String, Double>();
		data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 4.0);
		data.put("Just My Luck", 2.0);
		data.put("Superman Returns", 3.0);
		data.put("You, Me and Dupree", 2.0);
		data.put("The Night Listener", 3.0);
		dictionary.put("Mick LaSalle", data);
		
		
		data = new HashMap<String, Double>();
		data.put("Lady in the Water", 3.0);
		data.put("Snakes on a Plane", 4.0);		
		data.put("Superman Returns", 5.0);
		data.put("You, Me and Dupree", 3.5);
		data.put("The Night Listener", 3.0);
		dictionary.put("Jack Matthews", data);
		


		data = new HashMap<String, Double>();		
		data.put("Snakes on a Plane", 4.5);		
		data.put("Superman Returns", 4.0);
		data.put("You, Me and Dupree", 1.0);
		dictionary.put("Toby", data);
		
		return dictionary;

    }
    
    public static HashMap<String,HashMap> infoTransform(){
    	HashMap<String,HashMap> dictionaryTransform=new HashMap<String, HashMap>();
    	
		HashMap<String, Double> data = new HashMap<String, Double>();
		data.put("Lisa Rose", 2.5);
		data.put("Gene Seymour", 3.0);
		data.put("Michael Phillips", 2.5);
		data.put("Mick LaSalle", 3.0);
		data.put("Jack Matthews", 3.0);			
		dictionaryTransform.put("Lady in the Water", data);
		
        
        data = new HashMap<String, Double>();
        data.put("Gene Seymour", 3.5);
		data.put("Lisa Rose", 3.5);
		data.put("Michael Phillips", 3.0);
		data.put("Claudia Puig", 3.5);
		data.put("Mick LaSalle", 4.0);
		data.put("Jack Matthews", 4.0);
		data.put("Toby", 4.0);
		dictionaryTransform.put("Snakes on a Plane", data);
		
		 data = new HashMap<String, Double>();
        data.put("Lisa Rose", 3.5);
		data.put("Gene Seymour", 5.0);		
		data.put("Michael Phillips", 3.5);		
		data.put("Claudia Puig", 4.0);
		data.put("Mick LaSalle", 3.0);
		data.put("Jack Matthews", 5.0);
		data.put("Toby", 4.0);
		dictionaryTransform.put("Superman Returns", data);
		
		data = new HashMap<String, Double>();
		data.put("Lisa Rose", 2.5);
		data.put("Gene Seymour", 3.5);
		data.put("Claudia Puig", 2.5);
		data.put("Mick LaSalle", 2.0);
		data.put("Jack Matthews", 3.5);
		data.put("Toby", 1.0);
		dictionaryTransform.put("You, Me and Dupree", data);       
			
		
		data = new HashMap<String, Double>();
		data.put("Lisa Rose", 3.0);
		data.put("Gene Seymour", 3.0);		
		data.put("Michael Phillips", 4.0);
		data.put("Claudia Puig", 4.5);
		data.put("Mick LaSalle", 3.0);
		data.put("Jack Matthews", 3.0);		
		dictionaryTransform.put("The Night Listener", data);
		


		data = new HashMap<String, Double>();		
		data.put("Lisa Rose", 3.0);		
		data.put("Gene Seymour", 1.5);
		data.put("Claudia Puig", 3.0);
		data.put("Mick LaSalle", 2.0);		
		
		dictionaryTransform.put("Just My Luck", data);
		
		return dictionaryTransform;

    }


}
